package com.mrx.commons.redis;

import com.mrx.commons.redis.adapter.FakeRedisTemplateAdapter;
import com.mrx.commons.redis.proxy.RedisTemplateProxy;
import com.mrx.commons.redis.proxy.ValueOperationsProxy;
import lombok.Getter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.lang.NonNull;

import java.time.Duration;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author Mr.X
 * @since 2022-09-18 12:26
 */
public class FakeRedisTemplate<K, V> extends FakeRedisTemplateAdapter<K, V> {

    private static final Map<Object, ValueWrapper> fakeRedis = new ConcurrentHashMap<>();

    private static final Logger logger = LoggerFactory.getLogger(FakeRedisTemplate.class);

    private final ValueOperations<K, V> valueOps;

    @Getter
    private final ApplicationEventPublisher publisher;

    protected FakeRedisTemplate(ApplicationEventPublisher publisher) {
        this.valueOps = ValueOperationsProxy.createProxy(new FakeValueOperations<>(fakeRedis, publisher));
        this.publisher = publisher;
    }

    public static <K, V> FakeRedisTemplate<K, V> getInstance(ApplicationEventPublisher publisher) {
        logger.debug("初始化 fakeRedis");
        return RedisTemplateProxy.createProxy(new FakeRedisTemplate<>(publisher));
    }

    @Override
    public Boolean delete(@NonNull K key) {
        boolean res = fakeRedis.containsKey(key);
        fakeRedis.remove(key);
        logger.debug("移除 key: {}", key);
        return res;
    }

    @Override
    public Boolean expire(@NonNull K key, @NonNull Duration timeout) {
        if (fakeRedis.containsKey(key)) {
            // 重新设置该对象的超时时间, 统一单位为 秒
            fakeRedis.get(key).setTimeout(timeout.toSeconds()).setUnit(TimeUnit.SECONDS);
            return true;
        }
        return false;
    }

    @NonNull
    @Override
    public ValueOperations<K, V> opsForValue() {
        return valueOps;
    }

    @Override
    @SuppressWarnings("unchecked")
    public Set<K> keys(@NonNull K pattern) {
        if (pattern instanceof String) {
            return (Set<K>) fakeRedis.keySet().stream()
                    .map(String.class::cast)
                    .filter(key -> key.matches((String) pattern))
                    .collect(Collectors.toSet());
        }
        throw new UnsupportedOperationException("支支持 String 类型的 key");
    }

}
